// ----------------------------------------------------------------------------
// ring_buffer.h
// ----------------------------------------------------------------------------
/*
 Description:
 リングバッファの基本クラス. 
 
 
 ----------------------------------------------------------------
 使い方.
 
 
 */
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/stdinteger.h>
#include <fw/base/core/noncopyable.h>
#include <fw/base/concurrent/atomic_intrinsic.h>

namespace fw
{
	class RingBufferControl : private NonCopyable
	{
	public:
		const uint32_t		m_size;
		uint32_t			m_current;
		uint32_t			m_write;
		uint32_t			m_read;
		
		 RingBufferControl(uint32_t bufferSize)
		: m_size	(bufferSize)
		, m_current	(0)
		, m_write	(0)
		, m_read	(0)
		{
		}
		
		~RingBufferControl()
		{
		}
		
		uint32_t Available() const
		{
			return Distance(m_read, m_current);
		}
		
		uint32_t Consume(uint32_t consumeSize) // Consumer
		{
			const uint32_t maxSize		= Distance(m_read, m_current);
			const uint32_t sizeNoSign	= uint32_and(consumeSize, 0x7fffffff);
			const uint32_t test			= uint32_sub(sizeNoSign, maxSize);
			const uint32_t testSize		= uint32_sels(test, consumeSize, maxSize);
			const uint32_t advance		= uint32_add(m_read, m_size);
			const uint32_t read			= uint32_mod(advance, m_size);
			m_read = read;
			
			return testSize;
		}
		
		uint32_t Reserve(uint32_t reserveSize) // Producer 
		{
			const uint32_t dist			= Distance(m_write, m_read)-1;
			const uint32_t maxSize		= uint32_sels(dist, m_size-1, dist);
			const uint32_t sizeNoSign	= uin32_and(reserveSize, 0x7fffffff);
			const uint32_t test			= uint32_sub(sizeNoSign, maxSize);
			const uint32_t size			= uint32_sels(test, reserveSize, maxSize);
			const uint32_t advance		= uint32_add(m_write, size);
			const uint32_t write		= uint32_mod(advance, m_size);
			m_write = write;
			
			return size;
		}
		
		uint32_t Commit(uint32_t commitSize) // Producer
		{
			
		}
		
		uint32_t Distance(uint32_t from, uint32_t to)
		{
			const uint32_t diff		= uint32_sub (to, from);
			const uint32_t le		= uint32_sub (m_size, diff);
			const uint32_t result	= uint32_sels(diff, le, diff);
			
			return result;
		}
		
	}; // class RingBufferControl
	
	
} // namespace fw
